package com.swak.threads.utilization.wait;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.swak.threads.utilization.Wait;

/**
 * 等待
 * 
 * @author 618lf
 */
public class Level2 implements Wait {

	private static final int DEFAULT_RETRIES = 200;
	private static final long DEFAULT_SLEEP = 100;

	private final int retries = DEFAULT_RETRIES;
	private final long sleepTimeNs = DEFAULT_SLEEP;

	// wait
	private final Lock lock = new ReentrantLock();
	private final Condition processorNotifyCondition = lock.newCondition();

	@Override
	public void waitFor(BlockingQueue<Runnable> taskQueue) throws InterruptedException {
		int counter = retries;
		while (!this.hasTask(taskQueue)) {
			counter = applyWaitMethod(counter, sleepTimeNs);
		}
	}

	private boolean hasTask(BlockingQueue<Runnable> taskQueue) {
		try {
			return taskQueue.peek() != null;
		} catch (Exception e) {
			return false;
		}
	}

	private int applyWaitMethod(int counter, long timeout) throws InterruptedException {
		if (counter > 100) {
			--counter;
		} else if (counter > 0) {
			--counter;
			Thread.yield();
		} else {
			lock.lock();
			try {
				processorNotifyCondition.awaitNanos(Math.min(sleepTimeNs, timeout));
			} finally {
				lock.unlock();
			}
		}

		return counter;
	}

	@Override
	public void wakeup() {
		lock.lock();
		try {
			processorNotifyCondition.signalAll();
		} finally {
			lock.unlock();
		}
	}
}
